<?php

declare(strict_types=1);

/*
 * This file is part of Sulu.
 *
 * (c) Sulu GmbH
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Sulu\Content\Infrastructure\Sulu\Admin;

use Sulu\Bundle\AdminBundle\Admin\View\DropdownToolbarAction;
use Sulu\Bundle\AdminBundle\Admin\View\FormViewBuilderInterface;
use Sulu\Bundle\AdminBundle\Admin\View\ListItemAction;
use Sulu\Bundle\AdminBundle\Admin\View\PreviewFormViewBuilderInterface;
use Sulu\Bundle\AdminBundle\Admin\View\ToolbarAction;
use Sulu\Bundle\AdminBundle\Admin\View\ViewBuilderFactoryInterface;
use Sulu\Bundle\AdminBundle\Admin\View\ViewBuilderInterface;
use Sulu\Bundle\PreviewBundle\Preview\Object\PreviewObjectProviderRegistryInterface;
use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCheckerInterface;
use Sulu\Content\Application\ContentMetadataInspector\ContentMetadataInspectorInterface;
use Sulu\Content\Domain\Model\ExcerptInterface;
use Sulu\Content\Domain\Model\SeoInterface;
use Sulu\Content\Domain\Model\ShadowInterface;
use Sulu\Content\Domain\Model\TaxonomyInterface;
use Sulu\Content\Domain\Model\TemplateInterface;
use Sulu\Content\Domain\Model\WorkflowInterface;

/**
 * @final
 */
class ContentViewBuilderFactory implements ContentViewBuilderFactoryInterface
{
    /**
     * @param array<string, array{instanceOf: class-string}> $settingsForms
     * @param array<string, array{instanceOf: class-string}> $excerptForms
     * @param array<string, array{instanceOf: class-string}> $seoForms
     */
    public function __construct(
        private ViewBuilderFactoryInterface $viewBuilderFactory,
        private PreviewObjectProviderRegistryInterface $objectProviderRegistry,
        private ContentMetadataInspectorInterface $contentMetadataInspector,
        private SecurityCheckerInterface $securityChecker,
        private array $settingsForms,
        private array $excerptForms = [],
        private array $seoForms = []
    ) {
    }

    public function getDefaultToolbarActions(
        string $contentRichEntityClass
    ): array {
        $dimensionContentClass = $this->contentMetadataInspector->getDimensionContentClass($contentRichEntityClass);

        $toolbarActions = [];

        if (\is_subclass_of($dimensionContentClass, WorkflowInterface::class)) {
            $toolbarActions['save'] = new ToolbarAction(
                'sulu_admin.save_with_publishing',
                [
                    'publish_visible_condition' => '(!_permissions || _permissions.live)',
                    'save_visible_condition' => '(!_permissions || _permissions.edit)',
                ]
            );
        } else {
            $toolbarActions['save'] = new ToolbarAction(
                'sulu_admin.save'
            );
        }

        if (\is_subclass_of($dimensionContentClass, TemplateInterface::class)) {
            $toolbarActions['type'] = new ToolbarAction(
                'sulu_admin.type',
                [
                    'disabled_condition' => '(_permissions && !_permissions.edit)',
                ],
            );
        }

        $toolbarActions['delete'] = new ToolbarAction(
            'sulu_admin.delete',
            [
                'visible_condition' => '(!_permissions || _permissions.delete) && url != "/"',
            ]
        );

        if (\is_subclass_of($dimensionContentClass, WorkflowInterface::class)) {
            $toolbarActions['edit'] = new DropdownToolbarAction(
                'sulu_admin.edit',
                'su-pen',
                [
                    new ToolbarAction(
                        'sulu_admin.delete_draft',
                        [
                            'visible_condition' => '(!_permissions || _permissions.live)',
                        ]
                    ),
                    new ToolbarAction(
                        'sulu_admin.set_unpublished',
                        [
                            'visible_condition' => '(!_permissions || _permissions.live)',
                        ]
                    ),
                ]
            );
        }

        return $toolbarActions;
    }

    public function createViews(
        string $contentRichEntityClass,
        string $editParentView,
        ?string $addParentView = null,
        ?string $securityContext = null,
        ?array $toolbarActions = null
    ): array {
        $dimensionContentClass = $this->contentMetadataInspector->getDimensionContentClass($contentRichEntityClass);

        $resourceKey = $dimensionContentClass::getResourceKey();
        $previewEnabled = $this->objectProviderRegistry->hasPreviewObjectProvider($resourceKey);

        $toolbarActions = $toolbarActions ?: $this->getDefaultToolbarActions($contentRichEntityClass);
        $addToolbarActions = $toolbarActions;

        $settingsToolbarActions = [];
        $seoAndExcerptToolbarActions = [];
        if (isset($toolbarActions['save'])) {
            $seoAndExcerptToolbarActions = ['save' => $toolbarActions['save']];
            $settingsToolbarActions = ['save' => $toolbarActions['save']];
        }
        if (isset($toolbarActions['edit'])) {
            $seoAndExcerptToolbarActions['edit'] = $toolbarActions['edit'];
            $settingsToolbarActions['edit'] = $toolbarActions['edit'];
        }

        if (!$this->hasPermission($securityContext, PermissionTypes::EDIT)) {
            unset($toolbarActions['save'], $seoAndExcerptToolbarActions['save'], $settingsToolbarActions['save']);
        }

        if (!$this->hasPermission($securityContext, PermissionTypes::LIVE)) {
            unset($toolbarActions['edit'], $addToolbarActions['edit']);
        }

        if (!$this->hasPermission($securityContext, PermissionTypes::DELETE)) {
            unset($toolbarActions['delete'], $addToolbarActions['delete']);
        }

        $views = [];

        if ($this->hasPermission($securityContext, PermissionTypes::ADD)) {
            if ($addParentView) {
                if (\is_subclass_of($dimensionContentClass, TemplateInterface::class)) {
                    /** @var FormViewBuilderInterface|PreviewFormViewBuilderInterface $templateFormView */
                    $templateFormView = $this->createTemplateFormView(
                        $addParentView,
                        false,
                        $resourceKey,
                        $dimensionContentClass::getTemplateType(),
                        $addToolbarActions
                    );

                    $templateFormView->setEditView($editParentView);

                    $views[] = $templateFormView;
                }
            }
        }

        if ($this->hasPermission($securityContext, PermissionTypes::EDIT)) {
            if (\is_subclass_of($dimensionContentClass, TemplateInterface::class)) {
                $views[] = $this->createTemplateFormView(
                    $editParentView,
                    $previewEnabled,
                    $resourceKey,
                    $dimensionContentClass::getTemplateType(),
                    $toolbarActions
                );
            }

            if (\is_subclass_of($dimensionContentClass, SeoInterface::class)) {
                $views[] = $this->createSeoFormView(
                    $editParentView,
                    $previewEnabled,
                    $resourceKey,
                    $seoAndExcerptToolbarActions,
                    $dimensionContentClass
                );
            }

            if (\is_subclass_of($dimensionContentClass, ExcerptInterface::class)
                || \is_subclass_of($dimensionContentClass, TaxonomyInterface::class)
            ) {
                $views[] = $this->createExcerptFormView(
                    $editParentView,
                    $previewEnabled,
                    $resourceKey,
                    $seoAndExcerptToolbarActions,
                    $dimensionContentClass
                );
            }

            if (\is_subclass_of($dimensionContentClass, ShadowInterface::class)) {
                foreach ($views as $view) {
                    if ($view instanceof FormViewBuilderInterface || $view instanceof PreviewFormViewBuilderInterface) {
                        $view->setTabCondition('shadowOn != true');
                    }
                }
            }

            $views[] = $this->createSettingsFormView(
                $editParentView,
                $previewEnabled,
                $resourceKey,
                $settingsToolbarActions,
                $dimensionContentClass
            );

            $views = \array_merge(
                $views,
                $this->createInsightsFormViews(
                    $editParentView,
                    $resourceKey,
                )
            );
        }

        return $views;
    }

    /**
     * @param array<string, ToolbarAction> $toolbarActions
     */
    private function createTemplateFormView(
        string $parentView,
        bool $previewEnabled,
        string $resourceKey,
        string $formKey,
        array $toolbarActions
    ): ViewBuilderInterface {
        return $this->createFormViewBuilder($parentView . '.content', '/content', $previewEnabled)
            ->setResourceKey($resourceKey)
            ->setFormKey($formKey)
            ->setTabTitle('sulu_content.content')
            ->addToolbarActions(\array_values($toolbarActions))
            ->setTabOrder(20)
            ->setParent($parentView);
    }

    /**
     * @param array<string, ToolbarAction> $toolbarActions
     */
    private function createSeoFormView(
        string $parentView,
        bool $previewEnabled,
        string $resourceKey,
        array $toolbarActions,
        string $dimensionContentClass
    ): ViewBuilderInterface {
        $forms = [];
        foreach ($this->seoForms as $key => $tag) {
            if (\is_subclass_of($dimensionContentClass, $tag['instanceOf']) || $dimensionContentClass === $tag['instanceOf']) {
                $forms[] = $key;
            }
        }

        return $this->createFormViewBuilder($parentView . '.seo', '/seo', $previewEnabled)
            ->addMetadataRequestParameters(['forms' => $forms])
            ->setResourceKey($resourceKey)
            ->setFormKey('content_seo')
            ->setTabTitle('sulu_content.seo')
            ->setTitleVisible(true)
            ->addToolbarActions(\array_values($toolbarActions))
            ->setTabOrder(30)
            ->setParent($parentView);
    }

    /**
     * @param array<string, ToolbarAction> $toolbarActions
     */
    private function createExcerptFormView(
        string $parentView,
        bool $previewEnabled,
        string $resourceKey,
        array $toolbarActions,
        string $dimensionContentClass
    ): ViewBuilderInterface {
        $forms = [];
        foreach ($this->excerptForms as $key => $tag) {
            if (\is_subclass_of($dimensionContentClass, $tag['instanceOf']) || $dimensionContentClass === $tag['instanceOf']) {
                $forms[] = $key;
            }
        }

        $hasExcerpt = \is_subclass_of($dimensionContentClass, ExcerptInterface::class);
        $tabTitle = $hasExcerpt ? 'sulu_content.excerpt' : 'sulu_content.taxonomies';

        return $this->createFormViewBuilder($parentView . '.excerpt', '/excerpt', $previewEnabled)
            ->addMetadataRequestParameters(['forms' => $forms])
            ->setResourceKey($resourceKey)
            ->setFormKey('content_excerpt')
            ->setTabTitle($tabTitle)
            ->setTitleVisible(true)
            ->addToolbarActions(\array_values($toolbarActions))
            ->setTabOrder(40)
            ->setParent($parentView);
    }

    /**
     * @param array<string, ToolbarAction> $toolbarActions
     */
    private function createSettingsFormView(
        string $parentView,
        bool $previewEnabled,
        string $resourceKey,
        array $toolbarActions,
        string $dimensionContentClass
    ): ViewBuilderInterface {
        $forms = [];
        foreach ($this->settingsForms as $key => $tag) {
            if (\is_subclass_of($dimensionContentClass, $tag['instanceOf']) || $dimensionContentClass === $tag['instanceOf']) {
                $forms[] = $key;
            }
        }

        return $this->createFormViewBuilder($parentView . '.settings', '/settings', $previewEnabled)
            ->addMetadataRequestParameters(['forms' => $forms])
            ->setResourceKey($resourceKey)
            ->setFormKey('content_settings')
            ->setTabTitle('sulu_content.settings')
            ->setTitleVisible(true)
            ->addToolbarActions(\array_values($toolbarActions))
            ->setTabOrder(50)
            ->setParent($parentView);
    }

    /**
     * @return array<ViewBuilderInterface>
     */
    private function createInsightsFormViews(
        string $parentView,
        string $resourceKey,
        ?string $versionsResourceKey = null,
        ?string $versionsListKey = null,
    ): array {
        $insightsResourceTabViewName = $parentView . '.insights';

        if (null === $versionsResourceKey) {
            $versionsResourceKey = $resourceKey . '_versions';
        }

        if (null === $versionsListKey) {
            $versionsListKey = $resourceKey . '_versions';
        }

        return [
            $this->viewBuilderFactory
                ->createResourceTabViewBuilder($insightsResourceTabViewName, '/insights')
                ->setResourceKey($resourceKey)
                ->setTabOrder(6144)
                ->setTabTitle('sulu_admin.insights')
                ->addRouterAttributesToBackView(['webspace'])
                ->setParent($parentView),

            $this->viewBuilderFactory
                ->createListViewBuilder($insightsResourceTabViewName . '.versions', '/versions')
                ->setTabTitle('sulu_admin.versions')
                ->setResourceKey($versionsResourceKey)
                ->setListKey($versionsListKey)
                ->addListAdapters(['table'])
                ->addAdapterOptions([
                    'table' => [
                        'skin' => 'flat',
                    ],
                ])
                ->disableTabGap()
                ->disableSearching()
                ->disableSelection()
                ->disableColumnOptions()
                ->disableFiltering()
                ->addRouterAttributesToListRequest(['id', 'webspace'])
                ->addItemActions([
                    new ListItemAction('restore_version', ['success_view' => $parentView]),
                ])
                ->setParent($insightsResourceTabViewName),
        ];
    }

    /**
     * @return PreviewFormViewBuilderInterface|FormViewBuilderInterface
     */
    private function createFormViewBuilder(string $name, string $path, bool $previewEnabled): ViewBuilderInterface
    {
        if ($previewEnabled) {
            return $this->viewBuilderFactory->createPreviewFormViewBuilder($name, $path);
        }

        return $this->viewBuilderFactory->createFormViewBuilder($name, $path);
    }

    private function hasPermission(?string $securityContext, string $permissionType): bool
    {
        if (!$securityContext) {
            return true;
        }

        return $this->securityChecker->hasPermission($securityContext, $permissionType);
    }
}
